home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume22 / average / part01 next >
Encoding:
Text File  |  1991-08-12  |  9.8 KB  |  376 lines

  1. Newsgroups: comp.sources.misc
  2. From: Liudvikas Bukys <bukys@cs.rochester.edu>
  3. Subject:  v22i001:  average - average data in multiple input files, Part01/01
  4. Message-ID: <1991Aug13.035017.23751@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: 147533dbf9bb4ac79efb6e07d2becee7
  6. Date: Tue, 13 Aug 1991 03:50:17 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Liudvikas Bukys <bukys@cs.rochester.edu>
  10. Posting-number: Volume 22, Issue 1
  11. Archive-name: average/part01
  12. Environment: UNIX
  13.  
  14. I wrote this years ago, and a colleague liked it so much that I wrote
  15. a man page and a Makefile and now it's in your hands.  
  16.  
  17. average produces a composite data file from many similar input files.
  18. average takes multiple files containing text  (which  should be the 
  19. same in all files) and numbers (which may differ from file to file), 
  20. and it outputs one file, with the same text, and with each occurence
  21. of a number replaced by its average over all of the input files.
  22.  
  23. I find this program useful for averaging the timing output from several
  24. runs of a program.
  25.  
  26. Liudvikas Bukys
  27. <bukys@cs.rochester.edu>
  28. ---
  29. #! /bin/sh
  30. # This is a shell archive.  Remove anything before this line, then unpack
  31. # it by saving it into a file and typing "sh file".  To overwrite existing
  32. # files, type "sh file -c".  You can also feed this as standard input via
  33. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  34. # will see the following message at the end:
  35. #        "End of shell archive."
  36. # Contents:  average.1 average.c Makefile
  37. # Wrapped by bukys@stork.cs.rochester.edu on Fri Aug  9 12:20:26 1991
  38. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  39. if test -f 'average.1' -a "${1}" != "-c" ; then 
  40.   echo shar: Will not clobber existing file \"'average.1'\"
  41. else
  42. echo shar: Extracting \"'average.1'\" \(1370 characters\)
  43. sed "s/^X//" >'average.1' <<'END_OF_FILE'
  44. X.TH AVERAGE 1 "31 March 1987"
  45. X.SH NAME
  46. Xaverage \- produce a composite data file from many similar data files
  47. X.SH SYNOPSIS
  48. X.B average
  49. X.RB [ " \-m " ]
  50. X.IR filename \&.\|.\|.
  51. X.SH DESCRIPTION
  52. X.IX  "average command"  ""  "\fLaverage\fP \(em produce a composite data file from many similar data files"
  53. X.LP
  54. X.B average
  55. Xtakes multiple files containing
  56. Xtext (which should be the same in all files) and numbers (which
  57. Xmay differ from file to file), and it outputs one file, with
  58. Xthe same text, and with each occurence of a number replaced
  59. Xby its average over all of the input files.
  60. X.LP
  61. XThe numbers are output with precision matching the maximum precision
  62. Xpresent in the input, so integers remain integers, numbers with
  63. Xsix digits to the right of the decimal point will continue to be
  64. Xoutput with six digits, etc.
  65. X.LP
  66. XThe author finds this program useful for averaging the timing output
  67. Xfrom several runs of a program.
  68. X.SH OPTIONS
  69. X.TP
  70. X.B \-m
  71. XFor numbers whose values vary over the input files, output
  72. Xa [min,average,max] tuple instead of a single number.
  73. X.SH BUGS
  74. X.LP
  75. XThere is no support for numbers with 'e', 'E', or '+' in them
  76. X(e.g., numbers with exponents).
  77. X.LP
  78. XThe whole file is constructed in memory, which is not strictly
  79. Xnecessary, as the first file could be rescanned instead.
  80. X.SH AUTHOR
  81. X.LP
  82. XLiudvikas Bukys
  83. X<bukys@cs.rochester.edu>
  84. X.\" This code is in the public domain.
  85. END_OF_FILE
  86. if test 1370 -ne `wc -c <'average.1'`; then
  87.     echo shar: \"'average.1'\" unpacked with wrong size!
  88. fi
  89. # end of 'average.1'
  90. fi
  91. if test -f 'average.c' -a "${1}" != "-c" ; then 
  92.   echo shar: Will not clobber existing file \"'average.c'\"
  93. else
  94. echo shar: Extracting \"'average.c'\" \(5247 characters\)
  95. sed "s/^X//" >'average.c' <<'END_OF_FILE'
  96. X/*
  97. X * average -- produce a composite file from multiple, similar, files
  98. X *
  99. X *    This general-purpose program takes multiple files containing
  100. X *    text (which should be the same in all files) and numbers (which
  101. X *    may differ from file to file), and it outputs one file, with
  102. X *    the same text, and with each occurence of a number replaced
  103. X *    by its average over all of the input files.  There is an option
  104. X *    for outputting [min,average,max] tuples instead of a single number.
  105. X *
  106. X * HISTORY
  107. X *
  108. X *    1987/03/31    Liudvikas Bukys <bukys@cs.rochester.edu>
  109. X *
  110. X *        Version 1.0 created.
  111. X *
  112. X *        I needed it to compute some average runtimes from several
  113. X *        timing runs of some multiprocessor code.
  114. X *
  115. X *        There is no support for numbers with 'e', 'E', or '+' in
  116. X *        them.  Those characters would be parsed as text.
  117. X *
  118. X *        The whole file is sucked into memory.
  119. X */
  120. X
  121. X#define USAGE "USAGE:  %s [-m] file1 [file2 ...]\n"
  122. X
  123. X#include <stdio.h>
  124. X#include <ctype.h>
  125. X
  126. Xextern char *malloc();
  127. Xextern char *strchr();    /* or try index() if you don't have strchr() */
  128. X
  129. X#define MAX(a,b)    (((a)>(b))?(a):(b))
  130. X#define MIN(a,b)    (((a)<(b))?(a):(b))
  131. X
  132. Xstruct token
  133. X    {
  134. X    struct token *next;
  135. X    char *buffer;
  136. X    int precision;
  137. X    double average, min, max;
  138. X    int count;
  139. X    } head = { 0, };
  140. X
  141. X/*
  142. X * MAXTOKENLEN doesn't show through to the user, who doesn't care whether
  143. X * a bunch of text is parsed as a single 20000-byte token or a pile of
  144. X * 512-byte tokens.  The only thing it might affect would be if you had
  145. X * numbers with length > MAXTOKENLEN, but this code doesn't have any
  146. X * bignum support anyway.
  147. X */
  148. X#define MAXTOKENLEN 512
  149. X
  150. X
  151. Xmain(argc, argv)
  152. Xint argc;
  153. Xchar **argv;
  154. X    {
  155. X    register int i;
  156. X    register FILE *f;
  157. X    register struct token *p;
  158. X    int minmaxflag = 0;
  159. X
  160. X    if (argc <= 1)
  161. X        {
  162. X        (void) fprintf(stderr, USAGE, argv[0]);
  163. X        exit(1);
  164. X        }
  165. X
  166. X    /*
  167. X     * Read in each of my input files and tokenize it.
  168. X     */
  169. X    for (i= 1; i < argc; i++)
  170. X        if (argv[i][0] == '-')
  171. X            if (argv[i][1] == 'm')
  172. X                minmaxflag = 1;
  173. X            else
  174. X                {
  175. X                (void) fprintf(stderr, USAGE, argv[0]);
  176. X                exit(1);
  177. X                }
  178. X        else if ((f= fopen(argv[i], "r")) != NULL)
  179. X            {
  180. X            for (p= &head;  !feof(f);  p= p->next)
  181. X                readword(p, f);
  182. X            (void) fclose(f);
  183. X            }
  184. X        else
  185. X            perror(argv[i]);
  186. X
  187. X    /*
  188. X     * Output the token list.
  189. X     * Numbers retain the maximum precision of the input numbers.
  190. X     */
  191. X    for (p = head.next;  p;  p = p->next)
  192. X        if (p->buffer)
  193. X            (void) printf("%s", p->buffer);
  194. X        else if (p->precision == 0)
  195. X            if (p->min == p->max)
  196. X                (void) printf("%d", (int) p->min);
  197. X            else if (minmaxflag)
  198. X                (void) printf("[%d %d %d]", (int) p->min, (int) p->average, (int) p->max);
  199. X            else
  200. X                (void) printf("%d", (int) p->average);
  201. X        else
  202. X            if (p->min == p->max)
  203. X                (void) printf("%.*lf", p->precision-1, p->min);
  204. X            else if (minmaxflag)
  205. X                (void) printf("[%.*lf %.*lf %.*lf]",
  206. X                    p->precision-1, p->min,
  207. X                    p->precision-1, p->average,
  208. X                    p->precision-1, p->max);
  209. X            else
  210. X                (void) printf("%.*lf", p->precision-1, p->average);
  211. X
  212. X    exit (0);
  213. X    }
  214. X
  215. X/*
  216. X * Read one token -- either a number or a text string.
  217. X */
  218. Xreadword(ptail, f)
  219. Xstruct token *ptail;
  220. XFILE *f;
  221. X    {
  222. X    register struct token *p;
  223. X    register int c, hasdigit, wasseparator;
  224. X    register unsigned len;
  225. X    char tok[MAXTOKENLEN+1];
  226. X
  227. X    /*
  228. X     * get next token, or add a new one to the end of the list
  229. X     */
  230. X    if (p= ptail->next)
  231. X        ;
  232. X    else if (ptail->next = p = (struct token *) malloc(sizeof *p))
  233. X        {
  234. X        p->next = 0;
  235. X        p->buffer = 0;
  236. X        p->count = 0;
  237. X        p->precision = 0;
  238. X        }
  239. X    else
  240. X        {
  241. X        (void) fprintf(stderr, "malloc failed\n");
  242. X        exit(1);
  243. X        }
  244. X    
  245. X    c = getc(f);
  246. X    (void) ungetc(c, f);
  247. X    if (strchr("0123456789.-", c))
  248. X        {
  249. X        /*
  250. X         * possibly data -- defer judgement until after I see some
  251. X         * digits (this might just be a string of '-', after all).
  252. X         */
  253. X        len = 0;
  254. X        hasdigit = 0;
  255. X        while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
  256. X            if (strchr("0123456789.-", c))
  257. X                {
  258. X                tok[len++] = c;
  259. X                if (strchr("0123456789", c))
  260. X                    hasdigit = 1;
  261. X                }
  262. X            else
  263. X                {
  264. X                (void) ungetc(c, f);
  265. X                break;
  266. X                }
  267. X        tok[len] = '\0';
  268. X        if (hasdigit)
  269. X            dodata(p, tok, len);
  270. X        else
  271. X            dotext(p, tok, len);
  272. X        }
  273. X    else
  274. X        {
  275. X        /*
  276. X         * text
  277. X         */
  278. X        wasseparator = 0;
  279. X        len = 0;
  280. X        while (len < MAXTOKENLEN && ((c= getc(f)) != EOF))
  281. X            if (wasseparator && strchr("0123456789.-", c))
  282. X                {
  283. X                (void) ungetc(c, f);
  284. X                break;
  285. X                }
  286. X            else
  287. X                {
  288. X                tok[len++] = c;
  289. X                wasseparator = !isascii(c) || !isalnum(c);
  290. X                }
  291. X        tok[len] = '\0';
  292. X        dotext(p, tok, len);
  293. X        }
  294. X    }
  295. X
  296. X/*
  297. X * Do number-specific processing -- compute min, max, average
  298. X */
  299. Xdodata(p, tok, len)
  300. Xstruct token *p;
  301. Xchar *tok;
  302. Xunsigned len;
  303. X    {
  304. X    char *dot;
  305. X    double value;
  306. X
  307. X    if (dot= strchr(tok, '.'))
  308. X        p->precision = MAX(p->precision, (tok+len)-dot);
  309. X
  310. X    value = 0.0;
  311. X    (void) sscanf(tok, "%lf", &value);
  312. X
  313. X    if (p->count++)
  314. X        {
  315. X        p->min = MIN(p->min, value);
  316. X        p->max = MAX(p->max, value);
  317. X        p->average = p->average*((p->count-1.0)/(p->count)) + value/p->count;
  318. X        }
  319. X    else
  320. X        p->min = p->max = p->average = value;
  321. X    }
  322. X
  323. X/*
  324. X * Do text-specific processing -- save the text permanently (but only the first time!)
  325. X */
  326. Xdotext(p, tok, len)
  327. Xstruct token *p;
  328. Xchar *tok;
  329. Xunsigned len;
  330. X    {
  331. X    if (p->buffer)
  332. X        ; /* remember the old string only */
  333. X    else if (p->buffer= malloc(len+1))
  334. X        bcopy(tok, p->buffer, len+1);
  335. X    else
  336. X        {
  337. X        (void) fprintf(stderr, "malloc failed\n");
  338. X        exit(1);
  339. X        }
  340. X    }
  341. END_OF_FILE
  342. if test 5247 -ne `wc -c <'average.c'`; then
  343.     echo shar: \"'average.c'\" unpacked with wrong size!
  344. fi
  345. # end of 'average.c'
  346. fi
  347. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  348.   echo shar: Will not clobber existing file \"'Makefile'\"
  349. else
  350. echo shar: Extracting \"'Makefile'\" \(111 characters\)
  351. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  352. Xall: average
  353. X
  354. Xclean:
  355. X    rm -f average average.o
  356. X
  357. X#####
  358. X
  359. Xaverage: average.o
  360. X    $(CC) $(CFLAGS) -o average average.o
  361. END_OF_FILE
  362. if test 111 -ne `wc -c <'Makefile'`; then
  363.     echo shar: \"'Makefile'\" unpacked with wrong size!
  364. fi
  365. # end of 'Makefile'
  366. fi
  367. echo shar: End of shell archive.
  368. exit 0
  369.  
  370. exit 0 # Just in case...
  371. -- 
  372. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  373. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  374. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  375. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  376.